#include "device.h"
#include "component.h"
#include "audio.h"
#include "audio_num.h"
#include "debug_config.h"
#define AUDIO_LOG(format, ...) TASK_LOG("[audio_oneLine.c] " C_LIGHT_GREEN format C_NONE, ##__VA_ARGS__)

/* 默认语音组件的昵称 */
#ifndef KOS_PARAM_AUDIO_ALIAS
#define KOS_PARAM_AUDIO_ALIAS AUDIO_ALIAS_FRONT
#endif

/* NV AUDIO组件初始化标识*/
#define AUDIO_NV_INIT_FLAG 0xFA

/* 扫描语音设备状态事件 */
#define EVENT_SCAN_DEV_STA (0X00000001)

 //#define EVENT_PLAY_AUDIO (0X00000002)//01

/* 定义缓存大小 */
#define AUDIO_RING_BUFFER_LEN (40)
#define AUDIO_RING_BUFFER_SIZE (sizeof(uint16_t))

// 正在播放以下声音时，禁止播放其它语音
const uint16_t prohibitPlayTab[] =
    {
        YI_TUI_CHU_GUAN_LI_MO_SHI, // 已退出管理模式
};

// 在设置为静音模式下,下面的语音仍然可以正常播放
const uint16_t muteInvalidTab[] =
    {
        BAO_JING_YIN_DA_DA_DA,                                                // 报警音嗒嗒嗒
        JING_YIN_MO_SHI,                                                      // 静音模式
        YI_JIN_RU_GUAN_LI_MO_SHI,                                             // 已进入管理模式
        // DIAN_LIANG_DI_QING_GENG_HUAN_DIAN_CHI,                                // 电量低，请更换电池
        MEN_WEI_SHANG_SUO,                                                    // 门未上锁
        XI_TONG_YI_SUO_DING_QING_SHAO_HOU_ZAI_SHI,                            // 系统已锁定，请稍后再试
        // QING_ZAI_MEN_WAI_AN_JING_HAO_JIAN_QUE_REN_CAO_ZUO,                    // 请在门外按#号键确认操作
        DIAN_CHI_DIAN_LIANG_BU_ZU_QING_GENG_HUAN_DIAN_CHI, // 电池电量低，请及时更换电池或充电
};

/* 创建环形缓存，保存待播放的语音索引号 */
static RingBufferHandle_t rbAudioHandle = NULL;

/* 语音nv信息 */
__EFRAM static AuidoNv_stu_t nvAudioInfo;

/* 记录当前正在播放的语音序号 */
static uint16_t active_audio_num = 0;

/* 语音状态（0：空闲   1：忙） */
static FlagStatus audio_status = RESET;

/* 禁止播放标志（正在播放不可打断的语音该标志为1） */
static FlagStatus prohibit_play = RESET;

static uint8_t Disable_Mute_Flag = 0; /* 禁止静音标志 */

/**
 * @brief  设置语言
 * @note
 */
static ErrorStatus Audio_SetLanguageApi(uint8_t lan)
{
    uint8_t tmp = lan;
    nvAudioInfo.language = lan;
    OSAL_NvWrite(OSAL_OFFSET(AuidoNv_stu_t, language), &tmp, sizeof(tmp));
    AUDIO_LOG("SetLanguage = %d\r\n", lan);
    return SUCCESS;
}

/**
 * @brief  设置音量
 * @note
 */
static ErrorStatus Audio_SetVolumeApi(uint8_t vol)
{
    if (vol <= 100)
    {
        int32_t ret = Device_Write(vAUDIO_1, "VOLUME", strlen("VOLUME"), vol);
        if (ret == -1)
        {
            return ERROR;
        }
        nvAudioInfo.volume = vol;
        OSAL_NvWrite(OSAL_OFFSET(AuidoNv_stu_t, volume), &nvAudioInfo.volume, sizeof(nvAudioInfo.volume));
        return SUCCESS;
    }
    else
    {
        return ERROR;
    }
}

/**
 * @brief  设置静音模式
 * @note
 */
static ErrorStatus Audio_SetMuteApi(uint8_t flag)
{
    nvAudioInfo.mute = flag;
    OSAL_NvWrite(OSAL_OFFSET(AuidoNv_stu_t, mute), &nvAudioInfo.mute, sizeof(nvAudioInfo.mute));
    return SUCCESS;
}

/**
 * @brief  Audio组件NV初始化
 * @note
 */
static void Audio_NvInit(void)
{
    __EFRAM static FlagStatus power_on = RESET;

    if (power_on != SET)
    {
        power_on = SET;

        //< 读出数据
        memset(&nvAudioInfo, 0, sizeof(nvAudioInfo));
        OSAL_NvRead(0, &nvAudioInfo, sizeof(AuidoNv_stu_t));
        //< NV RESET
        if (nvAudioInfo.nvInitFlag != AUDIO_NV_INIT_FLAG)
        {
            AUDIO_LOG("Audio Nv Reset\r\n");
            nvAudioInfo.nvInitFlag = AUDIO_NV_INIT_FLAG;
            nvAudioInfo.language = LANGUAGE_ENGLISH; // DEFAULT_LANGUAGE
            nvAudioInfo.volume = 100;
            nvAudioInfo.mute = RESET;
            //< 读语音版本
            OSAL_NvWrite(0, &nvAudioInfo, sizeof(nvAudioInfo));

            //< 音量设置到底层驱动  -- 单线串口 常供电语音IC 不需要每次唤醒都设置音量
            Device_Write(vAUDIO_1, "VOLUME", strlen("VOLUME"), nvAudioInfo.volume);
        }
    }
    
}

/**
 * @brief  当前语音是否在prohibitPlayTab里面
 * @note
 * @param  audioIndex： 语音索引
 * @return SET:在prohibitPlayTab里面 RESET：不在prohibitPlayTab里面
 */
static FlagStatus Audio_IsProhibit(uint16_t audioIndex)
{
    uint8_t j;
    uint8_t tabLen = OSAL_LENGTH(prohibitPlayTab);

    for (j = 0; j < tabLen; j++)
    {
        if (audioIndex % AUDIO_LANGUAGE_ADDR_OFFSET == prohibitPlayTab[j])
        {
            return SET;
        }
    }
    return RESET;
}

/**
 * @brief  当前语音是否在静音无效列表里面
 * @note
 * @param  audioIndex： 语音索引
 * @return SET:在prohibitPlayTab里面 RESET：不在prohibitPlayTab里面
 */
static FlagStatus Audio_IsMuteInvalidTab(uint16_t audioIndex)
{
    uint8_t j;
    uint8_t tabLen = OSAL_LENGTH(muteInvalidTab);
    for (j = 0; j < tabLen; j++)
    {
        if (audioIndex % AUDIO_LANGUAGE_ADDR_OFFSET == muteInvalidTab[j])
        {
            return SET;
        }
    }
    return RESET;
}

/**
 * @brief  播放下一条待播放的语音
 *
 * @note
 */
static ErrorStatus Audio_PlayNext(uint16_t sn)
{
    Device_Write(vAUDIO_1, "PLAY", strlen("PLAY"), sn);
    return SUCCESS;
}

/**
 * @brief  语音设备空闲中断处理
 *
 * @note
 */
static void Audio_IdleISR(void)
{
    AUDIO_LOG("audio_status = RESET\r\n");
    audio_status = RESET;
}

static void DoorBell_Close_cb(TimerHandle_stu_t handle)
{
    // AUDIO_LOG("doorbell close\r\n");
    Device_Write(vPIN_C20, NULL, 0, 1);
}

/**
 * @brief  使能AUDIO
 * @note
 * @param  sn： 播放的编号
 * @param  opt：1：立即播
 *              2：空闲才播
 *              其他值：排队播
 * @return 成功/失败
 */
static ErrorStatus Audio_PlayApi(uint16_t sn, uint8_t opt)
{
    if (sn == 0)
    {
        return ERROR; // 无效语音编号
    }
    if (prohibit_play == SET)
    {
        // 正在播放prohibitPlayTab列表里面的条目，禁止播放其它语音
        return ERROR;
    }

    if ((audio_status != RESET) && (opt == 2))
    {
        // opt参数为2：当前语音正忙就不播
        return ERROR;
    }

    AUDIO_LOG("Audio_PlayApi\r\n");
    if (sn > YU_YIN_Z && sn < AUDIO_LANGUAGE_ADDR_OFFSET)
    {
        sn += nvAudioInfo.language * AUDIO_LANGUAGE_ADDR_OFFSET;
    }
    AUDIO_LOG("sn = %d\r\n", sn);

    if (opt == 1 || sn == STOP_PLAY)
    {
        OSAL_RingBufferReset(rbAudioHandle); // Reset Ringbuffer
        audio_status = RESET;
    }

    if (sn != STOP_PLAY)
    {
        if (Disable_Mute_Flag != 0 || nvAudioInfo.mute == RESET || Audio_IsMuteInvalidTab(sn))
        {
            // 非静音状态、或者在静音无效表里面：则需要写入播放队列
            OSAL_RingBufferWrite(rbAudioHandle, &sn);
            OSAL_EventSingleCreate(COMP_AUDIO, EVENT_SCAN_DEV_STA, 0, EVT_PRIORITY_MEDIUM);
            OSAL_EventRepeatCreate(COMP_AUDIO, EVENT_SCAN_DEV_STA, 50, EVT_PRIORITY_MEDIUM);

            if (Audio_IsProhibit(sn) == SET)
            {
                prohibit_play = SET;
            }
        }
    }
    return SUCCESS;
}

/**
 * @brief  将字符串转换成语音编号
 *
 */
static uint8_t Audio_string2audio(uint8_t *str, uint16_t *audio)
{
    uint16_t num, cnt = 0;

    while (*str != '\0')
    {
        num = 0;
        if (*str == '0')
        {
            num = YU_YIN_0;
        }
        else if (*str >= '1' && *str <= '9')
        {
            num = YU_YIN_1 + (*str - '1');
        }
        else if (*str >= 'A' && *str <= 'Z')
        {
            num = YU_YIN_A + (*str - 'A');
        }
        else if (*str >= 'a' && *str <= 'z')
        {
            num = YU_YIN_A + (*str - 'a');
        }
        else if (*str == '-')
        {
            num = ZHI_WEN_YIN_DO;
        }
        str++;
        if (num != 0)
        {
            audio[cnt++] = num;
        }
    }
    audio[cnt++] = ZHI_WEN_YIN_DO;
    return cnt;
}

/**
 * @brief  播放字符串
 *
 */
static ErrorStatus Audio_PlayStringApi(char *str)
{
    uint16_t audioBuffer[30], len;

    len = Audio_string2audio((uint8_t *)str, audioBuffer);
    for (int i = 0; i < len; i++)
    {
        Audio_PlayApi(audioBuffer[i], RESET);
    }
    return SUCCESS;
}

/**
 * @brief  扫描设备状态
 *
 * @note
 */
static void Audio_ScanDeviceStatus(void)
{
    if (audio_status == RESET) // 当前语音播放结束
    {
        /* 通知应用层当前这句播放结束 */
        if ((active_audio_num != 0))
        {
            AudioPublishMsg_t msg;
            msg.number = active_audio_num;
            OSAL_MessagePublish(&msg, sizeof(msg));

            if (Audio_IsProhibit(active_audio_num) == SET)
            {
                prohibit_play = RESET;
            }
        }

        /* 播放下一句 */
        uint16_t number;
        if (OSAL_RingBufferRead(rbAudioHandle, &number) != ERROR)
        {
            if (Audio_PlayNext(number) != ERROR)
            {
                audio_status = SET;
                active_audio_num = number;
                OSAL_SetTaskStatus(TASK_STA_ACTIVE);
            }
        }
        else
        {
            OSAL_EventDelete(COMP_AUDIO, EVENT_SCAN_DEV_STA); // 删除扫描事件
            active_audio_num = 0;
            OSAL_SetTaskStatus(TASK_STA_NORMAL);
        }
    }
}

/**
 * @brief  语音中断处理
 * @note
 * @return
 */
static void Audio_Int_Irq_Handler(VirtualHardware_enum_t dev, void *data, uint32_t len)
{
    Audio_IdleISR();
}

static void Audio_Init(void)
{
    /* NV初始化 */
    Audio_NvInit();

    /* 配置语音组件的昵称 */
    OSAL_SetCompAlias(KOS_PARAM_AUDIO_ALIAS);

    /* 创建环形缓存、注册语音中断回调 */
    if (rbAudioHandle == NULL)
    {
        rbAudioHandle = OSAL_RingBufferCreate(AUDIO_RING_BUFFER_LEN, AUDIO_RING_BUFFER_SIZE);

        Device_RegisteredCB(vPIN_C40, Audio_Int_Irq_Handler);
    }
}

static void Audio_ProcessMbox(uint8_t *msg)
{
    uint16_t sn;

    switch (msg[0])
    {
    case AUDIO_MBOX_PLAY:
        memcpy(&sn, &msg[2], 2);
        Audio_PlayApi(sn, (FlagStatus)msg[1]);
        AUDIO_LOG("free mem size: %d, %d\r\n", OSAL_GetMinimumEverFreeHeapSize(), OSAL_GetFreeHeapSize());
        break;

    case AUDIO_MBOX_PLAYSTR:
        Audio_PlayStringApi((char *)&msg[1]);
        break;

    case AUDIO_MBOX_SET_LAN:
        Audio_SetLanguageApi(msg[1]);
        break;

    case AUDIO_MBOX_SET_VOL:
        Audio_SetVolumeApi(msg[1]);
        break;

    case AUDIO_MBOX_SET_MUTE:
        Audio_SetMuteApi(msg[1]);
        break;
    case AUDIO_MBOX_NOT_MUTE:
        if (msg[1] != 0)
        {
            Disable_Mute_Flag |= msg[2];
        }
        else
        {
            Disable_Mute_Flag &= ~msg[2];
        }
        break;
    }
}

/**
 * @brief  语音任务函数
 *
 * @note
 *
 * @param  event：当前任务的所有事件
 *
 * @return 返回未处理的事件
 */
static uint32_t Audio_Task(uint32_t event)
{
    /* 系统启动事件 */
    if (event & EVENT_SYS_START)
    {
        AUDIO_LOG("audio task start\r\n");
        Audio_Init();
        Device_Write(vPIN_C1, NULL, 0, 1);
        // Audio_PlayApi(HUAN_YING_YIN, RESET);
        Device_Enable(vAUDIO_1);

        // OSAL_EventRepeatCreate(COMP_AUDIO, EVENT_PLAY_AUDIO, 4000, EVT_PRIORITY_MEDIUM);//2000  02 

        return (event ^ EVENT_SYS_START);
    }

    /* 扫描设备状态事件 */
    if (event & EVENT_SCAN_DEV_STA)
    {
        Audio_ScanDeviceStatus();
        return (event ^ EVENT_SCAN_DEV_STA);
    }
    
        /* 语音播放测试事件 */
//    if (event & EVENT_PLAY_AUDIO)
//    {
//        static uint16_t palyNum = 0;

//        palyNum++;
//        Audio_PlayApi(palyNum, RESET);

//        if (palyNum == 162)
//        {
//            palyNum = 233;//
//        }
//        if(palyNum == 362)
//        {
//            palyNum = 0;
//        }
//        OSAL_UpdateSleepTime(10000,1);
//       return (event ^ EVENT_PLAY_AUDIO);
//    }

    if (event & EVENT_SYS_MBOX)
    {
        uint16_t size;
        while (OSAL_MboxLenght(&size) > 0)
        {
            uint8_t *mbox_buffer = (uint8_t *)OSAL_Malloc(size);
            if (mbox_buffer == NULL)
            {
                AUDIO_LOG("memory error\r\n");
                Device_EnterCritical();
                while (1)
                    ;
            }
            OSAL_MboxAccept(mbox_buffer);
            Audio_ProcessMbox(mbox_buffer);
            OSAL_Free(mbox_buffer);
        }
        return (event ^ EVENT_SYS_MBOX);
    }

    /* 系统休眠事件 */
    if (event & EVENT_SYS_SLEEP)
    {
        AUDIO_LOG("sleep\r\n");
        Device_Write(vPIN_C1, NULL, 0, 1);
        Device_Disable(vAUDIO_1);
        return (event ^ EVENT_SYS_SLEEP);
    }

    return 0;
}
COMPONENT_TASK_EXPORT(COMP_AUDIO, Audio_Task, sizeof(AuidoNv_stu_t));
